/*  This file is part of o.O.

    o.O is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    o.O is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with o.O.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2013 Oliver Katz */

/* WHAT'S UP?

This contains the most important part of o.O, the Builder class. It
builds recursive descent parsers. Start out with a new builder:
Builder b = Builder();

Now you need to add a grammar script. The parsers will be generated
from this in-program. You can then retrieve a master parser from the
builder which can be used to parse anything you want with your grammar.

If you have a grammar script stored in the string grammarScript, it can
be loaded as such:
b.create(Page(grammarScript));

If you are loading it from a file, use:
Page grammarScriptFromFile = Page();
grammarScriptFromFile.read("path/to/a/grammar/script.ogs");

The extention *.ogs isn't necessary.

So how do you write a grammar script? Let's start with a simple
example. Let's say we want to parse the following string:
"f(1, f(5))"

Let's say we have already tokenized it (for details see tokenizer.h):
'f' '(' '1' ',' 'f' '(' '5' ')' ')'

Let us start with a sequence parser, which parses things in a specific
order:
sequence function = name:function-name left:left-parenthesis argument-list right:right-parenthesis

This will create a new sequence parser called 'function'. It expects to
find a function name (which will be parsed with the parser called
'function-name'), a left parenthesis, a list of arguments, and a right
parenthesis. The 'function-name' parser will be quite easy. A leaf
parser expects a specific string, such as the function name 'f':
leaf function-name = f

In fact, we can use this for the parenthesis as well:
leaf left-parenthesis = (
leaf right-parenthesis = )

The argument list is a little more difficult. We need arguments
separated by commas. Let's start with the contents of the argument,
and worry about the commas in a second. The arguments can either be
numbers or function calls. We can use an only parser for the numbers,
which will only allow certain characters:
only number = 0123456789

Now to make the argument itself, it can be one of two things. For this,
we use a branch parser, which is a parser than can be one of a number
of things:
branch argument = number function

Now let us think of an argument list as a single comma-less argument
followed by a bunch of arguments prefixed with commas:
"firstArgument" ", secondArgument" ", thirdArgument" ...

Let's make a parser for an argument prefixed with a comma. Since we
need to parse something in an order, we use a sequence parser:
sequence argument-with-comma = comma argument

The comma parser is another leaf:
leaf comma = ,

Now to make the argument sequence:
sequence argument-list = argument some-arguments-with-commas

How do we make 'some-arguments-with-commas'? We need to have a parser
which can handle a variable number of instances of the same parser.
That's where the many parser comes in:
many some-arguments-with-commas = argument-with-comma

Now 'some-arguments-with-commas' can be one 'argument-with-comma', two
'argument-with-comma's, or none at all. 

Yay! We have finished the grammar script. The syntax for all the
different types of parsers are as follows:
leaf <NAME> = <SYMBOL>
only <NAME> = <LEGAL CHARACTERS>
sequence <NAME> = <LABEL>:<PARSER> <PARSER> ...
many <NAME> = <PARSER>
branch <NAME> = <PARSER> ...

There is also another parser called any. It's very simple. It will
accept any one token, no matter what. It is a wildcard. You can
access it with the parser name '*' at any time.

The syntax for sequence can be a little confusing. When you have a
sequence of parsers, you want to store some of them with labels and
some as unlabeled children. The thing about storing some parsers with
labels, is that they can only store a single token. Any parser that
results in something more complicated than a simple leaf or only needs
to be stored without a label. To store with a label:
sequence labeled = label:parser

To store without a label:
sequence unlabeled = parser

The finished grammar script should look something like the following.
You will note that the order has changed, because parsers cannot access
parsers which have not been declared yet through more than one level:
leat function-name = f
leat left-parenthesis = (
leat right-parenthesis = )
leat comma = ,
only number = 0123456789
branch argument = number function
sequence argument-with-comma = comma argument
many some-arguments-with-commas = argument-with-comma
sequence argument-list = argument some-arguments-with-commas
sequence function = name:function-name left:left-parenthesis argument-list right:right-parenthesis */

#ifndef __OO_PARSING_BUILDER_H
#define __OO_PARSING_BUILDER_H

#include "tokenizer.h"
#include "recursiveDescent.h"

namespace oO
{
	class Only : public Leaf
	{
	public:
		Only(std::string n, std::string m) : Leaf(n, m) {}
		std::pair<unsigned int, AST> check(std::vector<Token> t, Page p);
	};

	class Any : public Parser
	{
	public:
		Any() : Parser() {}
		std::pair<unsigned int, AST> check(std::vector<Token> t, Page p);
	};

	class Builder
	{
	private:
		std::map<std::string, Parser*> parsers;

	public:
		Builder() {}
		Builder &operator << (Parser *p);
		Parser *operator [] (std::string n);
		void enableAllDebugging();
		void disableAllStrict();
		Branch createAnyBranch();
		Leaf createLeaf(std::string n, std::string s);
		Only createOnly(std::string n, std::string s);
		Any createAny();
		Sequence createSequence(std::string n, std::vector<std::pair<std::string, std::string> > s);
		Many createMany(std::string n, std::string s);
		Branch createBranch(std::string n, std::vector<std::string> s);
		Builder &create(Page p);
	};
}

#endif
